package com.x.epspace.ext;

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ReadPreference;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
  
public class MongoFactoryBean extends AbstractFactoryBean<Mongo> {
 
     // 表示服务器列表(主从复制或者分片)的字符串数组
     private String[] serverStrings;
     // mongoDB配置对象
     private MongoClientOptions mongoOptions;
     // 是否主从分离(读取从库)，默认读写都在主库
     private boolean readSecondary = false;
     // 设定写策略(出错时是否抛异常)，默认采用SAFE模式(需要抛异常)
     private WriteConcern writeConcern = WriteConcern.SAFE;
      
     private int connectionsPerHost = 10;
     
     private int connectTimeout = 10000;
     
     private boolean cursorFinalizerEnabled = true;
     
     private int maxWaitTime = 120000;
     
     private int threadsAllowedToBlockForConnectionMultiplier = 5;
     
     private int socketTimeout = 0;
     
     private boolean socketKeepAlive = false;
     
     private int w = 0;
     
     private int wtimeout = 0;
     
     private boolean fsync = false;
     
     private boolean j = false;
 
     @Override
     public Class<?> getObjectType() {
         return Mongo.class;
     }

     @Override
     protected Mongo createInstance() throws Exception {
         Mongo mongo = initMongo();
         
         // 设定主从分离
         if (readSecondary) {
             mongo.setReadPreference(ReadPreference.secondaryPreferred());
         }
 
         // 设定写策略
         mongo.setWriteConcern(writeConcern);
         return mongo;
     }
     
     /**
      * 初始化mongo实例
      * @return
      * @throws Exception
      */
     private Mongo initMongo() throws Exception {
         // 根据条件创建Mongo实例
         Mongo mongo = null;
         mongoOptions = getClientOptions();
         
         List<ServerAddress> serverList = getServerList();
 
         if (serverList.size() == 0) {
             mongo = new MongoClient();
         }else if(serverList.size() == 1){
             if (mongoOptions != null) {
                 mongo = new MongoClient(serverList.get(0), mongoOptions);
             }else{
                 mongo = new MongoClient(serverList.get(0));
             }
         }else{
             if (mongoOptions != null) {
                 mongo = new MongoClient(serverList, mongoOptions);
             }else{
                 mongo = new MongoClient(serverList);
             }
         }
         return mongo;
     }
     
     private MongoClientOptions getClientOptions(){
    	 if(mongoOptions != null) return mongoOptions;
    	 MongoClientOptions.Builder build = new MongoClientOptions.Builder(); 
    	 build.connectionsPerHost(connectionsPerHost);
    	 build.connectTimeout(connectTimeout);
    	 build.cursorFinalizerEnabled(cursorFinalizerEnabled);
    	 build.maxWaitTime(maxWaitTime);
    	 build.threadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier);
    	 build.socketTimeout(socketTimeout);
    	 build.socketKeepAlive(socketKeepAlive);
    	 
    	 writeConcern.withFsync(fsync);
    	 writeConcern.withW(w);
    	 writeConcern.withW(wtimeout);
    	 writeConcern.withJ(j);
    	 
    	 build.writeConcern(writeConcern);
    	 return build.build();
     }
     
     
     /**
      * 根据服务器字符串列表，解析出服务器对象列表
      * <p>
      * 
      * @Title: getServerList
      *         </p>
      * 
      * @return
      * @throws Exception
      */
     private List<ServerAddress> getServerList() throws Exception {
         List<ServerAddress> serverList = new ArrayList<ServerAddress>();
         try {
             for (String serverString : serverStrings) {
                 String[] temp = serverString.split(":");
                 String host = temp[0];
                 if (temp.length > 2) {
                     throw new IllegalArgumentException(
                             "Invalid server address string: " + serverString);
                 }
                 if (temp.length == 2) {
                     serverList.add(new ServerAddress(host, Integer
                             .parseInt(temp[1])));
                 } else {
                     serverList.add(new ServerAddress(host));
                 }
             }
             return serverList;
         } catch (Exception e) {
             throw new Exception(
                     "Error while converting serverString to ServerAddressList",
                     e);
         }
     }

	public String[] getServerStrings() {
		return serverStrings;
	}

	public void setServerStrings(String[] serverStrings) {
		this.serverStrings = serverStrings;
	}

	public MongoClientOptions getMongoOptions() {
		return mongoOptions;
	}

	public void setMongoOptions(MongoClientOptions mongoOptions) {
		this.mongoOptions = mongoOptions;
	}

	public boolean isReadSecondary() {
		return readSecondary;
	}

	public void setReadSecondary(boolean readSecondary) {
		this.readSecondary = readSecondary;
	}

	public WriteConcern getWriteConcern() {
		return writeConcern;
	}

	public void setWriteConcern(WriteConcern writeConcern) {
		this.writeConcern = writeConcern;
	}

	public int getConnectionsPerHost() {
		return connectionsPerHost;
	}

	public void setConnectionsPerHost(int connectionsPerHost) {
		this.connectionsPerHost = connectionsPerHost;
	}

	public int getConnectTimeout() {
		return connectTimeout;
	}

	public void setConnectTimeout(int connectTimeout) {
		this.connectTimeout = connectTimeout;
	}

	public boolean isCursorFinalizerEnabled() {
		return cursorFinalizerEnabled;
	}

	public void setCursorFinalizerEnabled(boolean cursorFinalizerEnabled) {
		this.cursorFinalizerEnabled = cursorFinalizerEnabled;
	}

	public int getMaxWaitTime() {
		return maxWaitTime;
	}

	public void setMaxWaitTime(int maxWaitTime) {
		this.maxWaitTime = maxWaitTime;
	}

	public int getThreadsAllowedToBlockForConnectionMultiplier() {
		return threadsAllowedToBlockForConnectionMultiplier;
	}

	public void setThreadsAllowedToBlockForConnectionMultiplier(
			int threadsAllowedToBlockForConnectionMultiplier) {
		this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
	}

	public int getSocketTimeout() {
		return socketTimeout;
	}

	public void setSocketTimeout(int socketTimeout) {
		this.socketTimeout = socketTimeout;
	}

	public boolean isSocketKeepAlive() {
		return socketKeepAlive;
	}

	public void setSocketKeepAlive(boolean socketKeepAlive) {
		this.socketKeepAlive = socketKeepAlive;
	}

	public int getW() {
		return w;
	}

	public void setW(int w) {
		this.w = w;
	}

	public int getWtimeout() {
		return wtimeout;
	}

	public void setWtimeout(int wtimeout) {
		this.wtimeout = wtimeout;
	}

	public boolean isFsync() {
		return fsync;
	}

	public void setFsync(boolean fsync) {
		this.fsync = fsync;
	}

	public boolean isJ() {
		return j;
	}

	public void setJ(boolean j) {
		this.j = j;
	}
	
	
 
     /* ------------------- setters --------------------- */
 }